package com.caosy.grassthinkremote.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.caosy.grassthinkremote.common.BaseContext;
import com.caosy.grassthinkremote.common.GtrConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

/**
 * Spring Security过滤器链
 * @author c-caosy
 * @date 2024-07-09
 */
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String token = extractRequestToken(httpServletRequest);//取出请求中的token
        //请求中有token，且token有效
        if (token != null && validateToken(token)) {
            UsernamePasswordAuthenticationToken auth
                    = new UsernamePasswordAuthenticationToken(null,null, Collections.emptyList());
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }

    private boolean validateToken(String token) {
        String existToken = (String) BaseContext.get(GtrConstant.LOCAL_MD5_TOKEN_KEY);//threadLocal中的token
        if (StrUtil.isBlank(existToken)) {
            //threadLocal中没有token，去redis中看是否有对应的key
            String redisKey = GtrConstant.REDIS_TOKEN_KEY_PREFIX + MD5.create().digestHex16(token);
            String redisUsername = (String) redisTemplate.opsForValue()
                    .get(redisKey);
            if (StrUtil.isNotBlank(redisUsername)) {
                //redis中有这个token，threadLocal中存放token和username
                BaseContext.set(GtrConstant.LOCAL_MD5_TOKEN_KEY, MD5.create().digestHex16(token));
                BaseContext.set(GtrConstant.LOCAL_USERNAME_KEY,redisUsername);
                //鉴权成功，返回true
                return true;
            }
        }
        //threadLocal有token，判断是否一致即可，防止客户端随便弄个接口来，前面的redis中如果token不一致也搜不到
        return StrUtil.equals(existToken,MD5.create().digest(token).toString());
    }

    private String extractRequestToken(HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("Authorization");
        return token;
    }
}
